
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

/*****************************************************************************
 *  Include Section
 *  add all #include here
 *****************************************************************************/
#include    <mach/pmu.h>
#include    <linux/sched.h>
#include    <linux/freezer.h>
#include    <linux/of_address.h>
#include    <linux/of_irq.h>
#include    <linux/of_platform.h>
#include    <linux/of_address.h>
#include    <mach/clock.h>
#include <mach/fh_sadc_plat.h>
#include <linux/iio/iio.h>
#include <linux/io.h>
#include <linux/scatterlist.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/scatterlist.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/bug.h>
#include <linux/completion.h>
#include <linux/fs.h>
#include <linux/pm.h>

/*****************************************************************************
 * Define section
 * add all #define here
 *****************************************************************************/
#define FH_SADC_PROC_FILE    "driver/sadc"

#define wrap_readl(wrap, offset) \
	__raw_readl(wrap->regs + offset)

#define wrap_writel(wrap, offset, val) \
	__raw_writel((val), wrap->regs + offset)

static DECLARE_WAIT_QUEUE_HEAD(fh_sadc_hit_wait);
#define MAX_CHANNEL_NO	8
#define SADC_CTRL0			0x0
#define SADC_CTRL1			0x4
#define SADC_CTRL2			0x8
#define SADC_CONFIG0		0x10
#define SADC_CONFIG1		0x14
#define SADC_CONFIG2		0x18
#define SADC_CONFIG3		0x1c
#define SADC_CONFIG4		0x20
#define SADC_CONFIG5		0x24
#define SADC_CONFIG6		0x28
#define SADC_CONFIG7		0x2c
#define SADC_INT_EN			0x40
#define SADC_INT_STA		0x44
#define SADC_DOUT0			0x50
#define SADC_DOUT1			0x54
#define SADC_DOUT2			0x58
#define SADC_DOUT3			0x5c
#define SADC_BUTTON_DOUT0	0x60
#define SADC_BUTTON_DOUT1	0x64
#define SADC_BUTTON_DOUT2	0x68
#define SADC_BUTTON_DOUT3	0x6c
#define SADC_DEBUG0			0x100
#define SADC_DEBUG1			0x104
#define SADC_DEBUG2			0x108
#define SADC_DEBUG3			0x10c
#define SADC_DEBUG4			0x110
#define SADC_DEBUG5			0x114
#define SADC_DEBUG6			0x118
#define SADC_ECO			0x120

struct wrap_sadc_obj {
	void *regs;
	u32 irq_no;
	u32 frequency;
	u32 active_channel_no;
	uint16_t channel_data[MAX_CHANNEL_NO];
	spinlock_t lock;
	struct mutex		sadc_lock;
	struct completion done;
	int activebit;
	int refvol;
	struct clk  *clk;
	char isr_name[10];
};

struct iio_dev *fh_sadc_iio_obj;
/*****************************************************************************
 *
 *
 *		function body
 *
 *
 *****************************************************************************/
int fh_sadc_enable(struct wrap_sadc_obj *sadc)
{
	u32 control_reg;

	control_reg = wrap_readl(sadc, SADC_CTRL0);
	control_reg |= 1 << 0;
	wrap_writel(sadc, SADC_CTRL0, control_reg);
	return 0;
}

int fh_sadc_disable(struct wrap_sadc_obj *sadc)
{
	u32 control_reg;

	control_reg = wrap_readl(sadc, SADC_CTRL0);
	control_reg &= ~(1 << 0);
	wrap_writel(sadc, SADC_CTRL0, control_reg);
	return 0;
}

int fh_sadc_update(struct wrap_sadc_obj *sadc)
{
	u32 reg;

	reg = wrap_readl(sadc, SADC_CTRL1);
	reg |= 1;
	wrap_writel(sadc, SADC_CTRL1, reg);
	return 0;
}

int fh_sadc_lowpwr_enable(struct wrap_sadc_obj *sadc)
{
	u32 reg;

	reg = wrap_readl(sadc, SADC_CTRL2);
	reg |= (1 << 0);
	wrap_writel(sadc, SADC_CTRL2, reg);
	return 0;
}

u32 fh_sadc_lowpwr_disable(struct wrap_sadc_obj *sadc)
{
	u32 reg;

	reg = wrap_readl(sadc, SADC_CTRL2);
	reg &= (~(1 << 0));
	wrap_writel(sadc, SADC_CTRL2, reg);
	return 0;
}

int fh_sadc_continue_enable(u32 channel, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (channel >= MAX_CHANNEL_NO) {
		pr_err("channel num error %d\n", channel);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_CONFIG1);
	reg |= (1 << channel);
	wrap_writel(sadc, SADC_CONFIG1, reg);
	return 0;
}

int fh_sadc_continue_disable(u32 channel, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (channel >= MAX_CHANNEL_NO) {
		pr_err("channel num error %d\n", channel);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_CONFIG1);
	reg &= (~(1 << channel));
	wrap_writel(sadc, SADC_CONFIG1, reg);
	return 0;
}

int fh_sadc_single_enable(u32 channel, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (channel >= MAX_CHANNEL_NO) {
		pr_err("channel num error %d\n", channel);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_CONFIG0);
	reg |= (1 << channel);
	wrap_writel(sadc, SADC_CONFIG0, reg);
	return 0;
}

int fh_sadc_single_disable(u32 channel, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (channel >= MAX_CHANNEL_NO) {
		pr_err("channel num error %d\n", channel);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_CONFIG0);
	reg &= (~(1 << channel));
	wrap_writel(sadc, SADC_CONFIG0, reg);
	return 0;
}

int fh_sadc_eq_enable(u32 channel, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (channel >= MAX_CHANNEL_NO) {
		pr_err("channel num error %d\n", channel);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_CONFIG2);
	reg |= (1 << channel);
	wrap_writel(sadc, SADC_CONFIG2, reg);
	return 0;
}

int fh_sadc_eq_disable(u32 channel, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (channel >= MAX_CHANNEL_NO) {
		pr_err("channel num error %d\n", channel);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_CONFIG2);
	reg &= (~(1 << channel));
	wrap_writel(sadc, SADC_CONFIG2, reg);
	return 0;
}

int fh_sadc_hit_enable(u32 channel, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (channel >= MAX_CHANNEL_NO) {
		pr_err("channel num error %d\n", channel);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_CONFIG3);
	reg |= (1 << channel);
	wrap_writel(sadc, SADC_CONFIG3, reg);
	return 0;
}

int fh_sadc_hit_disable(u32 channel, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (channel >= MAX_CHANNEL_NO) {
		pr_err("sadc channel num error %d\n", channel);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_CONFIG3);
	reg &= (~(1 << channel));
	wrap_writel(sadc, SADC_CONFIG3, reg);
	return 0;
}

int fh_sadc_scan_time(u32 scan_time, struct wrap_sadc_obj *sadc)
{
	u32 value;

	value = scan_time*(sadc->frequency/1000);
	wrap_writel(sadc, SADC_CONFIG4, value);
	return 0;
}

int fh_sadc_glitch_time(u32 glitch_time, struct wrap_sadc_obj *sadc)
{
	u32 value;

	value = glitch_time*(sadc->frequency/1000);
	wrap_writel(sadc, SADC_CONFIG5, value);
	return 0;
}

int fh_sadc_noise_range(u32 noise_range, struct wrap_sadc_obj *sadc)
{
	u32 reg;
	u32 value;

	value = (noise_range*sadc->activebit)/sadc->refvol;
	value &= 0xfff;
	if (value >= 0xff) {
		pr_err("sadc noise range error %d\n", noise_range);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_CONFIG6);
	reg &= (~(0xff << 0));
	reg |= (value << 0);
	wrap_writel(sadc, SADC_CONFIG6, reg);
	return 0;
}

int fh_sadc_zero_value(u32 zero_value, struct wrap_sadc_obj *sadc)
{
	u32 reg;
	u32 value;

	value = (zero_value*sadc->activebit)/sadc->refvol;
	value &= 0xfff;

	reg = wrap_readl(sadc, SADC_CONFIG6);
	reg &= (~(0xfff << 16));
	reg |= (value << 16);
	wrap_writel(sadc, SADC_CONFIG6, reg);
	return 0;
}

int fh_sadc_active_bit(u32 active_bit, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (active_bit > 12) {
		pr_err("sadc active bit error %d\n", active_bit);
		return -1;
	}
	reg = 0xfff >> (12-active_bit);
	reg = reg << (12-active_bit);
	wrap_writel(sadc, SADC_CONFIG7, reg);
	return 0;
}

int fh_sadc_int_enable(u32 channel, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (channel > MAX_CHANNEL_NO) {
		pr_err("sadc channel num error %d\n", channel);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_INT_EN);
	reg |= (1 << channel);
	wrap_writel(sadc, SADC_INT_EN, reg);
	return 0;
}

int fh_sadc_int_disable(u32 channel, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (channel > MAX_CHANNEL_NO) {
		pr_err("sadc channel num error %d\n", channel);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_INT_EN);
	reg &= (~(1 << channel));
	wrap_writel(sadc, SADC_INT_EN, reg);
	return 0;
}

int fh_sadc_press_int_en(u32 channel, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (channel > MAX_CHANNEL_NO) {
		pr_err("sadc channel num error %d\n", channel);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_INT_EN);
	reg |= (1 << (channel + 8));
	wrap_writel(sadc, SADC_INT_EN, reg);
	return 0;
}

int fh_sadc_press_int_dis(u32 channel, struct wrap_sadc_obj *sadc)
{
	u32 reg;

	if (channel > MAX_CHANNEL_NO) {
		pr_err("sadc channel num error %d\n", channel);
		return -1;
	}
	reg = wrap_readl(sadc, SADC_INT_EN);
	reg &= (~(1 << (channel + 8)));
	wrap_writel(sadc, SADC_INT_EN, reg);
	return 0;
}
static int fh_lsadc_read_raw(struct iio_dev *indio_dev,
				    struct iio_chan_spec const *chan,
				    int *val, int *val2, long mask){
	u32 ret_time;
	struct wrap_sadc_obj *sadc = iio_priv(indio_dev);

	switch (mask) {
	case IIO_CHAN_INFO_RAW:
		mutex_lock(&sadc->sadc_lock);
		reinit_completion(&sadc->done);
		sadc->active_channel_no = 0xffffffff;
		fh_sadc_eq_enable(chan->channel, sadc);
		fh_sadc_active_bit(12, sadc);
		fh_sadc_continue_enable(chan->channel, sadc);
		fh_sadc_int_enable(chan->channel, sadc);
		/*10ms*/
		fh_sadc_scan_time(10, sadc);
		fh_sadc_enable(sadc);
		fh_sadc_update(sadc);
		ret_time = wait_for_completion_timeout(&sadc->done, 500);
		if (ret_time == 0) {
			pr_err("sadc timeout..\n");
			return -1;
		}

		if (chan->channel == sadc->active_channel_no)
			*val = (sadc->channel_data[chan->channel]*sadc->refvol)
			/sadc->activebit;
		else
			pr_err("sadc channel :%d,return channel:%d error\n",
			 chan->channel,sadc->active_channel_no);
		fh_sadc_eq_disable(chan->channel, sadc);
		fh_sadc_continue_disable(chan->channel, sadc);
		fh_sadc_int_disable(chan->channel, sadc);
		fh_sadc_update(sadc);
		mutex_unlock(&sadc->sadc_lock);
		return IIO_VAL_INT;
	case IIO_CHAN_INFO_SCALE:
		*val = sadc->refvol;
		*val2 = sadc->activebit;
		return IIO_VAL_INT_MULTIPLE;
	default:
		return -EINVAL;
	}
}
#if 0
u32 fh_sadc_isr_read_single_data(struct wrap_sadc_obj *sadc, u32 channel,
		u16 *buf) {
	u32 ret_time;

	reinit_completion(&sadc->done);
	sadc->active_channel_no = 0xffffffff;
	fh_sadc_active_bit(12);
	fh_sadc_single_enable(channel);
	fh_sadc_int_enable(channel);
	/*10ms*/
	fh_sadc_scan_time(10);
	fh_sadc_enable();
	fh_sadc_update();
	ret_time = wait_for_completion_timeout(&sadc->done, 500);
	if (ret_time == 0) {
		pr_err("sadc timeout..\n");
		return 1;
	}
	if (channel == sadc->active_channel_no)
		*buf = (sadc->channel_data[channel]*sadc->refvol)
		/sadc->activebit;
	else
		pr_err("sadc channel :%d,return channel:%d error\n", channel,
		sadc->active_channel_no);
	fh_sadc_single_disable(channel);
	fh_sadc_int_disable(channel);
	fh_sadc_update();
	return 0;
}

u32 fh_sadc_isr_read_hit_data(struct wrap_sadc_obj *sadc, u32 channel,
		u16 *buf) {

	sadc->active_channel_no = 0xffffffff;
	fh_sadc_active_bit(12);
	fh_sadc_continue_enable(channel);
	fh_sadc_hit_enable(channel);
	fh_sadc_press_int_en(channel);
	/*10ms*/
	fh_sadc_scan_time(10);
	fh_sadc_enable();
	fh_sadc_update();
	wait_event_freezable(fh_sadc_hit_wait,
	 channel == sadc->active_channel_no);
	*buf = (sadc->channel_data[channel]*sadc->refvol)
			/ sadc->activebit;
	fh_sadc_continue_disable(channel);
	fh_sadc_hit_disable(channel);
	fh_sadc_press_int_dis(channel);
	fh_sadc_update();
	return 0;
}
#endif
static irqreturn_t fh_sadc_isr(int irq, void *dev_id)
{

	u32 isr_status;
	u32 isr_active;
	u32 isr_en;
	u32 temp_data =  0;
	u32 channel = 0;
	u32 data = 0;
	struct wrap_sadc_obj *sadc = (struct wrap_sadc_obj *) dev_id;

	isr_status = wrap_readl(sadc, SADC_INT_STA);
	isr_en = wrap_readl(sadc, SADC_INT_EN);
	isr_active = isr_status & isr_en;
	if (isr_active & 0xff) {
		channel = ffs(isr_active);
		channel = channel - 1;
		switch (channel/2) {
		case 0:
			/*read channel 0 1*/
			temp_data = wrap_readl(sadc, SADC_DOUT0);
			break;
		case 1:
			/*read channel 2 3*/
			temp_data = wrap_readl(sadc, SADC_DOUT1);
			break;
		case 2:
			/*read channel 4 5*/
			temp_data = wrap_readl(sadc, SADC_DOUT2);
			break;
		case 3:
			/*read channel 6 7*/
			temp_data = wrap_readl(sadc, SADC_DOUT3);
			break;
		default:
			break;
		}
		complete(&(sadc->done));
	} else if (isr_active & 0xffff00) {
		if (isr_active & 0xff00)
			channel = ffs(isr_active >> 8);
		else
			channel = ffs(isr_active >> 16);
		channel = channel - 1;
		switch (channel/2) {
		case 0:
			/*read channel 0 1*/
			temp_data = wrap_readl(sadc, SADC_BUTTON_DOUT0);
			break;
		case 1:
			/*read channel 2 3*/
			temp_data = wrap_readl(sadc, SADC_BUTTON_DOUT1);
			break;
		case 2:
			/*read channel 4 5*/
			temp_data = wrap_readl(sadc, SADC_BUTTON_DOUT2);
			break;
		case 3:
			/*read channel 6 7*/
			temp_data = wrap_readl(sadc, SADC_BUTTON_DOUT3);
			break;
		default:
			break;
		}
		wake_up(&fh_sadc_hit_wait);
	}

	if (channel % 2)
		/*read high 16bit*/
		data = (temp_data >> 16) & 0xfff;
	else
		/*read low 16bit*/
		data = (temp_data & 0xfff);
	sadc->channel_data[channel] = data;
	sadc->active_channel_no = channel;
	wrap_writel(sadc, SADC_INT_STA, (~isr_status));
	return IRQ_HANDLED;
}

static struct of_device_id const fh_sadc_of_match[] = {
	{ .compatible = "fh,fh-sadc" },
	{}
};
MODULE_DEVICE_TABLE(of, fh_sadc_of_match);

static const struct iio_info fh_lsadc_iio_info = {
	.read_raw = fh_lsadc_read_raw,
	.driver_module = THIS_MODULE,
};

#define FH_LSADC_CHANNEL(_index, _id) {      \
	.type = IIO_VOLTAGE,                \
	.indexed = 1,						\
	.channel = _index,					\
	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |  \
			BIT(IIO_CHAN_INFO_SCALE),   \
	.datasheet_name = _id,              \
}

static const struct iio_chan_spec fh_lsadc_iio_channels[] = {
	FH_LSADC_CHANNEL(0, "adc0"),
	FH_LSADC_CHANNEL(1, "adc1"),
	FH_LSADC_CHANNEL(2, "adc2"),
	FH_LSADC_CHANNEL(3, "adc3"),
	FH_LSADC_CHANNEL(4, "adc4"),
	FH_LSADC_CHANNEL(5, "adc5"),
	FH_LSADC_CHANNEL(6, "adc6"),
	FH_LSADC_CHANNEL(7, "adc7"),
};

const struct iio_chan_spec fh_adckey_iio_channels=FH_LSADC_CHANNEL(1, "adc1");

struct iio_chan_spec * fh_adckey_iio_channel_get(void)
{
	return &fh_adckey_iio_channels;
}
EXPORT_SYMBOL(fh_adckey_iio_channels);

int fh_iio_read_channel_raw(struct iio_chan_spec *chan, int *val)
{
	int ret;
	int ad_raw_data2;

	if (NULL == fh_sadc_iio_obj)
		return -1;

	ret = fh_lsadc_read_raw(fh_sadc_iio_obj,
		 chan,
		 val, &ad_raw_data2, IIO_CHAN_INFO_RAW);
	return ret;
}
EXPORT_SYMBOL(fh_iio_read_channel_raw);

static void del_char(char *str, char ch)
{
	char *p = str;
	char *q = str;

	while (*q) {
		if (*q != ch)
			*p++ = *q;
		q++;
	}
	*p = '\0';
}

static ssize_t fh_sadc_proc_write(struct file *filp, const char *buf,
	 size_t len, loff_t *off)
{
	char message[32] = {0};
	char * const delim = ",";
	char *cur = message;
	int i;
	char *param_str[2];
	int ret;
	unsigned long param = 0;
	struct wrap_sadc_obj *sadc;

	sadc = iio_priv(fh_sadc_iio_obj);
	len = (len > 32) ? 32 : len;

	if (copy_from_user(message, buf, len))
		return -EFAULT;

	for (i = 0; i < 2; i++) {
		param_str[i] = strsep(&cur, delim);
		if (!param_str[i]) {
			pr_err("%s: ERROR: parameter[%d] is empty\n",
				__func__, i);
			pr_err("use like: sadclowpwr,1 or 0\n");
			return -EINVAL;
		} else {
			del_char(param_str[i], ' ');
			del_char(param_str[i], '\n');
		}
	}

	if (!strcmp(param_str[0], "sadclowpwr")) {
		ret = (u32)kstrtoul(param_str[1], 10, &param);
		param ? fh_sadc_lowpwr_enable(sadc)
		 : fh_sadc_lowpwr_disable(sadc);
	} else {
		pr_err("%s: ERROR: wrong parameter\n",
			 __func__);
		pr_err("use like: sadclowpwr,1 or 0\n");
		return -EINVAL;
	}

	return len;
}

static void *v_seq_start(struct seq_file *s, loff_t *pos)
{
	static unsigned long counter;

	counter = 0;
	if (*pos == 0)
		return &counter;
	else {
		*pos = 0;
		return NULL;
	}
}

static void *v_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	(*pos)++;
	return NULL;
}

static void v_seq_stop(struct seq_file *s, void *v)
{

}

static int v_seq_show(struct seq_file *sfile, void *v)
{
	int i;
	u32 ret;
	int ad_raw_data;
	int ad_raw_data2;

	seq_puts(sfile, "\nSADC Status:\n");
	for (i = 0; i < 8; i++) {
		ret = fh_lsadc_read_raw(fh_sadc_iio_obj,
		 &fh_lsadc_iio_channels[i],
		 &ad_raw_data, &ad_raw_data2, IIO_CHAN_INFO_RAW);
		if (ret != IIO_VAL_INT)
			seq_printf(sfile,
			 "contine sadc error code:0x%x\n", ret);
		else
			seq_printf(sfile, "continue read channel: %d \tvalue: %u\n",
					i, ad_raw_data);
	}

	return 0;
}

static const struct seq_operations iio_sadc_seq_ops = {
	.start = v_seq_start,
	.next = v_seq_next,
	.stop = v_seq_stop,
	.show = v_seq_show
};

static int fh_sadc_proc_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &iio_sadc_seq_ops);
}

static const struct file_operations fh_sadc_proc_ops = {
	.owner = THIS_MODULE,
	.open = fh_sadc_proc_open,
	.read = seq_read,
	.write = fh_sadc_proc_write,
	.release = seq_release,
};

static int fh_sadc_probe(struct platform_device *pdev)
{
	int err;
#ifdef CONFIG_USE_OF
	const struct of_device_id *match;
	struct device_node *np = pdev->dev.of_node;
#else
	struct resource *res;
	struct fh_sadc_platform_data *plat_data;
#endif
	struct clk  *sadc_clk;
	int irq;
	struct wrap_sadc_obj *info = NULL;

	fh_sadc_iio_obj = NULL;
	fh_sadc_iio_obj = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
	if (!fh_sadc_iio_obj) {
		dev_err(&pdev->dev, "failed allocating iio device\n");
		return -ENOMEM;
	}
	info = iio_priv(fh_sadc_iio_obj);
	sadc_clk = clk_get(&pdev->dev, "sadc_clk");
	if (IS_ERR(sadc_clk)) {
		err = PTR_ERR(sadc_clk);
		return -EPERM;
	}
	clk_prepare_enable(sadc_clk);
	info->clk = sadc_clk;
#ifdef CONFIG_FPGA
#define FPGA_SADC_CLOCK 15000000
	info->frequency = FPGA_SADC_CLOCK;
#else
	info->frequency = clk_get_rate(sadc_clk);
#endif
#ifdef CONFIG_USE_OF
		match = of_match_device(fh_sadc_of_match, &pdev->dev);
		if (!match) {
			pr_info("Failed to find sadc controller\n");
			return -ENODEV;
		}

		info->regs = of_iomap(np, 0);
		if (info->regs == NULL) {
			err = -ENXIO;
			return err;
		}

		irq = irq_of_parse_and_map(np, 0);
		if (irq < 0) {
			dev_err(&pdev->dev, "no irq resource\n");
			goto fail_no_ioremap;
		}
		of_property_read_u32(np, "ref-vol", &info->refvol);
		of_property_read_u32(np, "active-bit", &info->activebit);
#else
		plat_data = pdev->dev.platform_data;
		if (!plat_data) {
			dev_err(&pdev->dev, "sadc get platform data error..\n");
			return -ENODEV;
		}
		res = platform_get_resource(pdev,
			IORESOURCE_MEM, 0);
		if (!res) {
			dev_err(&pdev->dev, "sadc get platform source error..\n");
			return -ENODEV;
		}
		res = request_mem_region(res->start,
				resource_size(res), pdev->name);
		if (res == NULL) {
			dev_err(&pdev->dev, "sadc region already claimed\n");
			return -EBUSY;
		}
		info->refvol = plat_data->ref_vol;
		info->activebit = plat_data->active_bit;
		info->regs = ioremap(res->start, resource_size(res));
		if (info->regs == NULL) {
			err = -ENXIO;
			goto fail_no_ioremap;
		}
		irq = platform_get_irq(pdev, 0);
		irq = irq_create_mapping(NULL, irq);
		if (irq < 0) {
			dev_err(&pdev->dev, "no IRQ defined!\n");
			goto fail_no_ioremap;
		}
#endif

	info->irq_no = irq;
	init_completion(&info->done);
	mutex_init(&info->sadc_lock);
	info->active_channel_no = 0xffffffff;
	strncpy(info->isr_name, "sadc", sizeof("sadc"));
	err = request_irq(info->irq_no, fh_sadc_isr, 0,
			info->isr_name,
			info);
	if (err) {
		dev_dbg(&pdev->dev, "request_irq failed, %d\n", err);
		err = -ENXIO;
		goto err_irq;
	}
	platform_set_drvdata(pdev, fh_sadc_iio_obj);

	fh_sadc_iio_obj->name = dev_name(&pdev->dev);
	fh_sadc_iio_obj->dev.parent = &pdev->dev;
	fh_sadc_iio_obj->dev.of_node = pdev->dev.of_node;
	fh_sadc_iio_obj->info = &fh_lsadc_iio_info;
	fh_sadc_iio_obj->modes = INDIO_DIRECT_MODE;

	fh_sadc_iio_obj->channels = fh_lsadc_iio_channels;
	fh_sadc_iio_obj->num_channels = ARRAY_SIZE(fh_lsadc_iio_channels);
	err = devm_iio_device_register(&pdev->dev, fh_sadc_iio_obj);
	if (err < 0) {
		dev_err(&pdev->dev, "failed register iio device\n");
		return err;
	}
	if (!proc_create(FH_SADC_PROC_FILE,
		S_IRUGO, NULL, &fh_sadc_proc_ops))
		pr_err("%s: ERROR: %s proc file create failed",
		__func__, "SADC");
	return 0;

err_irq:
	iounmap(info->regs);

fail_no_ioremap:
#ifndef CONFIG_USE_OF
	release_mem_region(res->start, resource_size(res));
#endif
	return err;
}

static int __exit fh_sadc_remove(struct platform_device *pdev)
{

	struct resource *res;
	struct wrap_sadc_obj *info = NULL;
	struct iio_dev *indio_dev = NULL;

	indio_dev = platform_get_drvdata(pdev);
	info = iio_priv(indio_dev);
	if (info->clk) {
		clk_disable_unprepare(info->clk);
		clk_put(info->clk);
	}
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	free_irq(info->irq_no, info);
	iounmap(info->regs);
	devm_iio_device_unregister(&pdev->dev, indio_dev);
#ifndef CONFIG_USE_OF
	release_mem_region(res->start, resource_size(res));
#endif
	return 0;

}

#ifdef CONFIG_PM
static int adc_fh_runtime_suspend(struct device *dev)
{
	struct iio_dev *indio_dev = dev_get_drvdata(dev);
	struct wrap_sadc_obj *info = iio_priv(indio_dev);

	clk_disable_unprepare(info->clk);

	return 0;
}

static int adc_fh_runtime_resume(struct device *dev)
{
	struct iio_dev *indio_dev = dev_get_drvdata(dev);
	struct wrap_sadc_obj *info = iio_priv(indio_dev);
	int ret;

	ret = clk_prepare_enable(info->clk);
	if (ret)
		dev_err(dev, "can't enable ADC clock, ret=%d\n", ret);

	return ret;
}

UNIVERSAL_DEV_PM_OPS(adc_fh_pm_ops, adc_fh_runtime_suspend,
		   adc_fh_runtime_resume, NULL);

#define ADC_FH_PM_OPS (&adc_fh_pm_ops)
#else
#define ADC_FH_PM_OPS NULL
#endif /* CONFIG_PM */


/*******************
 *
 *
 *add platform cause of i need the board info...
 *in the probe function. i will register the sadc
 *misc drive...then the app can open the sadc misc device..
 *
 ******************/
static struct platform_driver fh_sadc_driver = {
	.driver	= {
		.name	= "fh_sadc",
		.owner	= THIS_MODULE,
		.of_match_table = fh_sadc_of_match,
		.pm = ADC_FH_PM_OPS,
	},
	.probe	= fh_sadc_probe,
	.remove	= __exit_p(fh_sadc_remove),
};



static int __init fh_sadc_init(void)
{
	return platform_driver_register(&fh_sadc_driver);
}

static void __exit fh_sadc_exit(void)
{

	platform_driver_unregister(&fh_sadc_driver);

}

module_init(fh_sadc_init);
module_exit(fh_sadc_exit);

MODULE_DESCRIPTION("fullhan sadc device driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("tangyh@fullhan.com");
MODULE_ALIAS("platform:FH_sadc");
